__author__ = 'Nguyen Duc Hai'
import time
from pymongo.errors import ConnectionFailure
import redis
import pymongo
from sqlalchemy import create_engine, MetaData
from sqlalchemy.exc import OperationalError


class MyRedis:
    def __init__(self, host='localhost', port=6379):
        self.host = host
        self.port = port
        self._conn = redis.Redis(host=self.host, port=self.port)
        self.connect()

    def connect(self):
        """
        Try to connect ro redis server until succeed
        """
        while True:
            try:
                self._conn.ping()
                break
            except redis.ConnectionError:
                print 'Reconnecting to redis at %s:%d' % (self.host, self.port)
            time.sleep(1)

    @property
    def conn(self):
        """
        Return a connection to redis server
        If the server is not available, try to connect until successful connected
        """
        self.connect()
        return self._conn


class MyMongo():
    def __init__(self, host='localhost', port=27017):
        self.host = host
        self.port = port
        self._conn = None
        self.connect()

    def connect(self):
        """
        Try to connect ro mongo server until succeed
        """
        while True:
            try:
                self._conn = pymongo.MongoClient(self.host, self.port)
                if self._conn.alive():
                    break
            except (ConnectionFailure, AssertionError):
                print 'Reconnecting to mongodb at %s:%d' % (self.host, self.port)
            time.sleep(1)

    @property
    def conn(self):
        """
        Return a connection to mongo server
        If the server is not available, try to connect until successful connected
        """
        try:
            if self._conn.alive():
                return self._conn
            else:
                self.connect()
        except (AssertionError, ConnectionFailure):
            self.connect()
        return self._conn


class MyMySQL():
    def __init__(self, db, user='root', password='admin', host='localhost', port=3306):
        self.addr = 'mysql://%s:%s@%s:%d/%s' % (user, password, host, port, db)
        self._engine = create_engine(self.addr)
        self._metadata = MetaData(bind=self._engine)
        self.reflect()

    def reflect(self):
        """
        Try to reflect until succeed
        """
        while True:
            try:
                self._metadata.reflect()
                break
            except OperationalError:
                print 'Reconnecting to MySQL at %s' % self.addr
            time.sleep(1)

    @property
    def metadata(self):
        return self._metadata

    @property
    def engine(self):
        return self._engine